package com.hk.commons.http.utils;

import com.hk.commons.util.CollectionUtils;
import com.hk.commons.util.ConverterUtils;
import com.hk.commons.util.StringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.hc.client5.http.classic.methods.HttpDelete;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
import org.apache.hc.client5.http.entity.mime.ContentBody;
import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.NameValuePair;
import org.apache.hc.core5.http.message.BasicHeader;
import org.apache.hc.core5.http.message.BasicNameValuePair;
import org.apache.hc.core5.net.WWWFormCodec;

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Http 工具类
 *
 * @author kevin
 * @date 2019-8-9 11:27
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public abstract class HttpUtils {

    public static final List<Header> DEFAULT_HEADER = Collections.singletonList(
            new BasicHeader(HttpHeaders.CONTENT_ENCODING, StandardCharsets.UTF_8.name()));

    /**
     * 请求时间配置
     * Socket超时 :10 秒
     * 连接超时:    5秒
     * 连接请求超时: 5秒
     */
    public static final RequestConfig DEFAULT_REQUEST_CONFIG = RequestConfig.custom()
            .setResponseTimeout(10, TimeUnit.SECONDS)//服务器返回数据(response)的时间，超过抛出read timeout
            .setConnectionRequestTimeout(5, TimeUnit.SECONDS) // 从连接池中获取连接的超时时间，超时间未拿到可用连接，会抛出org.apache.http.conn
            // .ConnectionPoolTimeoutException: Timeout waiting for connection from pool
            .build();


    /**
     * 创建 http Get 请求
     *
     * @param uri     　uri
     * @param params  请求参数
     * @param headers 请求头
     * @return {@link HttpGet}
     */
    public static HttpGet newHttpGet(String uri, Map<String, ?> params, Header... headers) {
        var get = new HttpGet(generateUri(uri, params));
        get.setHeaders(headers);
        return get;
    }

    /**
     * 创建 http Delete 请求
     *
     * @param uri     　uri
     * @param params  请求参数
     * @param headers 请求头
     * @return {@link HttpDelete}
     */
    public static HttpDelete newHttpDelete(String uri, Map<String, ?> params, Header... headers) {
        var httpDelete = new HttpDelete(generateUri(uri, params));
        httpDelete.setHeaders(headers);
        return httpDelete;
    }

    /**
     * 创建 http Post 请求
     *
     * @param uri     　uri
     * @param entity  请求参数
     * @param headers 请求头
     * @return {@link HttpPost}
     */
    public static HttpPost newHttpPost(String uri, HttpEntity entity, Header... headers) {
        var httpPost = new HttpPost(URI.create(uri));
        httpPost.setEntity(entity);
        httpPost.setHeaders(headers);
        return httpPost;
    }

    /**
     * 支持文件上传的转换为 请求体，请求参数不是放在 url后面 ?xx=xxx的形式，而是放在 body 中 xxx=xxx的形式。
     *
     * @param contentBody 　内容
     * @return {@link HttpEntity}
     */
    public static HttpEntity multipartHttpEntity(Map<String, ContentBody> contentBody) {
        var entityBuilder = MultipartEntityBuilder
                .create()
                .setStrictMode()
                .setCharset(StandardCharsets.UTF_8);
        if (CollectionUtils.isNotEmpty(contentBody)) {
            for (var entry : contentBody.entrySet()) {
                var value = entry.getValue();
                if (Objects.nonNull(value)) {
                    entityBuilder.addPart(entry.getKey(), value);
                }
            }
        }
        return entityBuilder.build();
    }

    /**
     * uri 请求参数 转换为 请求体
     *
     * @param params 　params
     * @return {@link HttpEntity}
     */
    public static HttpEntity toHttpEntity(Map<String, ?> params) {
        var nameValuePairs = new ArrayList<NameValuePair>();
        if (CollectionUtils.isNotEmpty(params)) {
            for (var entry : params.entrySet()) {
                var value = ConverterUtils.defaultConvert(entry.getValue(), String.class);
                if (StringUtils.isNotEmpty(value)) {
                    nameValuePairs.add(new BasicNameValuePair(entry.getKey(), value));
                }
            }
        }
        return new UrlEncodedFormEntity(nameValuePairs, StandardCharsets.UTF_8);
    }

    /**
     * uri 请求参数 拼装
     *
     * @param params 　params
     * @return 请求 uri 加参数
     */
    public static String generateUri(String uri, Map<String, ?> params) {
        var s = new StringBuilder(uri);
        if (CollectionUtils.isNotEmpty(params)) {
            var nameValuePairs = new ArrayList<NameValuePair>();
            params.forEach((key, value) -> {
                var convertValue = ConverterUtils.defaultConvert(value, String.class);
                if (StringUtils.isNotEmpty(convertValue)) {
                    nameValuePairs.add(new BasicNameValuePair(key, convertValue));
                }
            });
            if (!nameValuePairs.isEmpty()) {
                if (!StringUtils.endsWith(uri, "?")) {
                    s.append("?");
                }
                s.append(WWWFormCodec.format(nameValuePairs, StandardCharsets.UTF_8));
            }
        }
        return s.toString();
    }

}
